#pragma once

#include "Render/VulkanContext.h"
#include "AutoRecycleBuffer.h"

//大小固定的UniformBuffer
template<typename DataType>
class TVulkanUniformBuffer
{

public:
    TVulkanUniformBuffer()
    {
        vk::BufferCreateInfo BufferCreateInfo=vk::BufferCreateInfo()
            .setSize(sizeof(DataType))
            .setUsage(vk::BufferUsageFlagBits::eUniformBuffer)
            .setSharingMode(vk::SharingMode::eExclusive);

        AutoRecycleBuffer.Buffer=CVulkanContext::Get()->GetDevice().createBuffer(BufferCreateInfo);

        vk::MemoryRequirements MemoryRequirements=CVulkanContext::Get()->GetDevice().getBufferMemoryRequirements(AutoRecycleBuffer.Buffer);

        uint32_t MemoryTypeIndex=CVulkanContext::Get()->GetMemoryTypeIndex(MemoryRequirements, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);

        AutoRecycleBuffer.MemoryBlock=CVulkanContext::Get()->GetMemoryPools()->AllocateBlock(
            EVulkanMemoryUsage::UniformBuffer
            ,MemoryTypeIndex
            ,MemoryRequirements
            );

        CVulkanContext::Get()->GetDevice().bindBufferMemory(AutoRecycleBuffer.Buffer, AutoRecycleBuffer.MemoryBlock.Memory, AutoRecycleBuffer.MemoryBlock.Offset);
    }


    vk::Buffer GetBuffer() const { return AutoRecycleBuffer.Buffer; }
    uint32_t GetOffset() const { return 0; }
    constexpr uint32_t GetSize() const { return sizeof(DataType); }

    void WriteData(const DataType& Data)
    {
        void* DataPtr = CVulkanContext::Get()->GetDevice().mapMemory(AutoRecycleBuffer.MemoryBlock.Memory, AutoRecycleBuffer.MemoryBlock.Offset, sizeof(DataType));
        memcpy(DataPtr, &Data, sizeof(DataType));
        CVulkanContext::Get()->GetDevice().unmapMemory(AutoRecycleBuffer.MemoryBlock.Memory);
    }

protected:

    SVulkanAutoRecycleBuffer AutoRecycleBuffer;


};
